<!DOCTYPE html>
          <head>
        <meta charset="utf-8">
            
            <title>
                「Flask」0x03树莓派上使用Nginx和uWSGI部署Flask应用 | ttdevs
            </title>
            <meta content="width=device-width, initial-scale=1" name="viewport">
            <meta name="theme-color" content="#4184f3">
            
            
            <link href="/favicon.ico" rel="icon"/>
            

            <link rel="stylesheet" href="/css/highlight.light.css">
            <link rel="stylesheet" href="/css/prism-customize.css">
            <link rel="stylesheet" href="/css/nav-icon.css">
            <link rel="stylesheet" href="/css/waves.min.css">
            <link rel="stylesheet" href="/css/jquery.tocify.css">
            <link rel="stylesheet" href="/css/main.css">
            <link rel="stylesheet" href="/css/nav-indicator.css">
            
  

  
  <!-- 谷歌统计 -->
  <script>
    (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
    (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
    m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
    })(window,document,'script','//www.google-analytics.com/analytics.js','ga');

    ga('create', 'UA-97465173-1', 'auto');
    ga('send', 'pageview');

  </script>
  
            </meta>
        </meta>
    </head>

    <body>
        <header>
            <!-- cover image or sth. -->
        </header>
        <div id="main" class="m-scene">
            
<div class="nav-wrapper">

    <div class="container">
        <nav>
            <div class="logo wave">
                <a href="/" id="logo">
                    ttdevs
                </a>
            </div>
            <div class="nav-toggle-icon" >
                <div class="material-hamburger">
                    <span>
                    </span>
                    <span>
                    </span>
                    <span>
                    </span>
                </div>
            </div>
            <div class="menu-wrapper">
                <div class="nav-indicator">
                </div>
                <ul class="menus">
                    
                     
                        <li>
                            <a class="wave " href="/">
                                首页
                            </a>
                        </li>
                     
                        <li>
                            <a class="wave " href="/archives">
                                归档
                            </a>
                        </li>
                     
                        <li>
                            <a class="wave " href="/about">
                                关于
                            </a>
                        </li>
                     
                    
                   
                </ul>
            </div>
        </nav>
    </div>
</div>
            <div class="container content">
                <div class="scene_element scene_element--fadein">
                    <div class="row">
    <div class="main">
        <article>
          
          <header class="post-header with-cover" style="background-image:url('/1970/01/01/[Flask]0x03树莓派上使用Nginx和uWSGI部署Flask应用/cover.jpg')" >
          
          </header>
          <h1 class="post-title">「Flask」0x03树莓派上使用Nginx和uWSGI部署Flask应用</h1>

          <section class="post-info">
            <span class="post-date">1970/01/01</span>
            
            <span class="post-category">
                <a class="article-category-link" href="/categories/技术/">技术</a>
            </span>
            
            
            <span class="post-tags">
              <ul class="post-tag-list"><li class="post-tag-list-item"><a class="post-tag-list-link" href="/tags/Flask/">Flask</a></li></ul>
            </span>
            
          </section>

          <section class="post-content">
            <h2 id="0x00-部署：uWSGI-和-Nginx-介绍"><a href="/1970/01/01/[Flask]0x03树莓派上使用Nginx和uWSGI部署Flask应用/#0x00-部署：uWSGI-和-Nginx-介绍" class="headerlink" title="0x00 部署：uWSGI 和 Nginx 介绍"></a>0x00 部署：uWSGI 和 Nginx 介绍</h2><p>Deploy Flask Application with Nginx and uWSGI</p>
<p>考虑到部署的问题，相信您已经完成了自己Flask应用的开发工作，或者跟我一样，一个demo 应用已经完成。好奇自己的应用如何发布出去。接下来，通过介绍一些常用的工具来完成我们应用的部署。先简单介绍下我的环境：</p>
<ul>
<li>一台内网中的树莓派</li>
<li>一个花生棒(98RMB买的硬件)</li>
</ul>
<p>使用花生棒做了内网的端口映射，对外暴露80端口提供http服务，至于为什么这么做，请参考<a href="http://www.jianshu.com/p/9855c15a1dd7" target="_blank" rel="external">这里</a>。</p>
<p>好了，接下来进入正题。</p>
<p>uWSGI作为Web服务器使用，nginx做反向代理。</p>
<h3 id="uWSGI"><a href="/1970/01/01/[Flask]0x03树莓派上使用Nginx和uWSGI部署Flask应用/#uWSGI" class="headerlink" title="uWSGI"></a>uWSGI</h3><p>uWSGI做Web服务器</p>
<p>《Flask Web开发：基于Python的Web应用开发实战》有下面两段描述：</p>
<p>其一：</p>
<blockquote>
<p>Flask自带的开发Web服务器不够强健、安全和高效，无法在生产环境中使用。</p>
</blockquote>
<p>其二：</p>
<blockquote>
<p>Flask自带的开发Web服务器表现很差，因为它不是为生产环境设计的服务器。有两个可以在生产环境中使用、性能良好且支持Flask程序的服务器，分别是Gunicorn(<a href="http://gunicorn.org/" target="_blank" rel="external">http://gunicorn.org/</a>) 和 uWSGI(<a href="http://uwsgi-docs.readthedocs.org/en/latest/" target="_blank" rel="external">http://uwsgi-docs.readthedocs.org/en/latest/</a>) 。</p>
</blockquote>
<p>先介绍一下WSGI（from：<a href="https://zh.wikipedia.org/wiki/Web服务器网关接口" target="_blank" rel="external">维基百科</a>）：</p>
<blockquote>
<p>Web服务器网关接口（Python Web Server Gateway Interface，缩写为WSGI）是为Python语言定义的Web服务器和Web应用程序或框架之间的一种简单而通用的接口。自从WSGI被开发出来以后，许多其它语言中也出现了类似接口。<br>以前，如何选择合适的Web应用程序框架成为困扰Python初学者的一个问题，这是因为，一般而言，Web应用框架的选择将限制可用的Web服务器的选择，反之亦然。那时的Python应用程序通常是为CGI，FastCGI，mod_python中的一个而设计，甚至是为特定Web服务器的自定义的API接口而设计的。<br>WSGI[1] （有时发音作’wiz-gee’）是作为Web服务器与Web应用程序或应用框架之间的一种低级别的接口，以提升可移植Web应用开发的共同点。WSGI是基于现存的CGI标准而设计的。</p>
</blockquote>
<p>因此我们需要为我们的Flask应用配置一个 <code>Web服务器</code> 。《Flask Web开发》中介绍的部署到Heroku选择的是Gunicorn。Gunicorn  和 uWSGI 的比较网上很多，主要的问题可能就是谁的坑多坑少。经过比对，这里我选择uWSGI。</p>
<p>uWSGI 不仅仅是一个协议，同时也是一个应用服务器，可以服务于uWSGI、FastCGI和HTTP协议。uWSGI官方文档可参考<a href="http://uwsgi-docs.readthedocs.io/en/latest/" target="_blank" rel="external">这里</a> 。</p>
<p>支持WSGI的Web应用框架很多，比如：</p>
<ul>
<li>Django</li>
<li>Flask</li>
<li>web.py</li>
<li>web2py</li>
<li>Werkzeug</li>
<li>Tornado</li>
<li>and so on</li>
</ul>
<h3 id="Nginx"><a href="/1970/01/01/[Flask]0x03树莓派上使用Nginx和uWSGI部署Flask应用/#Nginx" class="headerlink" title="Nginx"></a>Nginx</h3><p>nginx做反向代理 </p>
<blockquote>
<p>Nginx（发音同engine x）是一个网页服务器，它能反向代理HTTP, HTTPS, SMTP, POP3, IMAP的协议链接，以及一个负载均衡器和一个HTTP缓存。</p>
<p>Nginx是一款面向性能设计的HTTP服务器，相较于Apache、lighttpd具有占有内存少，稳定性高等优势。与旧版本（&lt;=2.2）的Apache不同，nginx不采用每客户机一线程的设计模型，而是充分使用异步逻辑，削减了上下文调度开销，所以并发服务能力更强。整体采用模块化设计，有丰富的模块库和第三方模块库，配置灵活。 在Linux操作系统下，nginx使用epoll事件模型，得益于此，nginx在Linux操作系统下效率相当高。同时Nginx在OpenBSD或FreeBSD操作系统上采用类似于epoll的高效事件模型kqueue。</p>
<p>Nginx在官方测试的结果中，能够支持五万个平行连接，而在实际的运作中，是可以支持二万至四万个平行链接。</p>
</blockquote>
<p>以上来信息自<a href="https://zh.wikipedia.org/wiki/Nginx" target="_blank" rel="external">维基百科</a>。</p>
<p>反向代理：</p>
<blockquote>
<p>使用代理服务器可以将请求转发给内部的Web服务器，使用这种加速模式显然可以提升静态网页的访问速度。因此也可以考虑使用这种技术，让代理服务器将请求 均匀转发给多台内部Web服务器之一上，从而达到负载均衡的目的。这种代理方式与普通的代理方式有所不同，标准代理方式是客户使用代理访问多个外部Web 服务器，而这种代理方式是多个客户使用它访问内部Web服务器，因此也被称为反向代理模式。</p>
</blockquote>
<p>参考：<a href="http://www.bing.com/knows/反向代理负载均衡" target="_blank" rel="external">http://www.bing.com/knows/反向代理负载均衡</a></p>
<p>虽然你可能不知道Nginx是做什么的，但是你应该听过，再或者你至少听过Apache，他们都是HTTP服务器。恕我能力有限，目前为止并不能很好的解释为什么非得用Nginx，能告诉大家的是：Nginx帮我们处理很多静态资源，同时将动态请求转发给不同的Web服务器（负载均衡）。此处留坑，等以后补上。</p>
<p>接下来通过最简单的配置，将我们的Flask应用部署到我们的树莓派上，达到对部署的流程有个总体把握的目的。如果你需要更多的配置，可以参考各自部分的官方文档。</p>
<h2 id="0x01-uWSGI"><a href="/1970/01/01/[Flask]0x03树莓派上使用Nginx和uWSGI部署Flask应用/#0x01-uWSGI" class="headerlink" title="0x01 uWSGI"></a>0x01 uWSGI</h2><ul>
<li><p>安装</p>
<p>  先从安装说起：<code>pip install uwsgi</code></p>
</li>
<li><p>配置</p>
<p>  在我们项目的根目录下，创建 <code>uwsgi.ini</code> 文件， 内容如下：</p>
  <figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line">[uwsgi]</div><div class="line">socket = 127.0.0.1:5000</div><div class="line">processes = 4</div><div class="line">threads = 2</div><div class="line">plugins = python3</div><div class="line">master = true</div><div class="line">venv = venv</div><div class="line">pythonpath = .</div><div class="line">module = manage</div><div class="line">callable = application</div></pre></td></tr></table></figure>
<p>  配置参数说明：</p>
<ul>
<li>socket：应用程序所在地址，IP加端口号，当然，也可以有其他的形式</li>
<li>processes：开启的进程数量</li>
<li>threads：每个进程的线程数</li>
<li>plugins：加载的插件</li>
<li>module：加载指定的python WSGI模块</li>
<li><p>callable：在收到请求时，uWSGI加载的模块中哪个变量将被调用，默认是名字为“application”的变量。</p>
<p>顺便贴一下我的Flask项目文件：manage.py</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line"><span class="comment">#!/usr/bin/env python3</span></div><div class="line"><span class="comment"># coding:utf-8</span></div><div class="line"><span class="keyword">from</span> flask.ext.script <span class="keyword">import</span> Manager</div><div class="line">config = <span class="string">'development'</span></div><div class="line">application = create_app(config)</div><div class="line">manager = Manager(application)</div><div class="line">...</div><div class="line"><span class="keyword">if</span> __name__ == <span class="string">'__main__'</span>:</div><div class="line">        manager.run()</div></pre></td></tr></table></figure>
</li>
</ul>
</li>
</ul>
<ul>
<li><p>操作</p>
<p>  启动：<code>uwsgi uwsig.ini</code>。如果启动成功，会看到类似下面的log：</p>
  <figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div></pre></td><td class="code"><pre><div class="line">(venv)pi@raspberrypi:~/raspi $ uwsgi uwsgi.ini</div><div class="line">[uWSGI] getting INI configuration from uwsgi.ini</div><div class="line">open(&quot;./python3_plugin.so&quot;): No such file or directory [core/utils.c line 3684]</div><div class="line">!!! UNABLE to load uWSGI plugin: ./python3_plugin.so: cannot open shared object file: No such file or directory !!!</div><div class="line">*** Starting uWSGI 2.0.13.1 (32bit) on [Sun Jul  3 22:35:08 2016] ***</div><div class="line">compiled with version: 4.9.2 on 27 May 2016 15:15:57</div><div class="line">os: Linux-4.1.19-v7+ #858 树莓派 Tue Mar 15 15:56:00 GMT 2016</div><div class="line">nodename: raspberrypi</div><div class="line">machine: armv7l</div><div class="line">clock source: unix</div><div class="line">detected number of CPU cores: 4</div><div class="line">current working directory: /home/pi/raspi</div><div class="line">detected binary path: /home/pi/raspi/venv/bin/uwsgi</div><div class="line">!!! no internal routing support, rebuild with pcre support !!!</div><div class="line">your processes number limit is 6831</div><div class="line">your memory page size is 4096 bytes</div><div class="line">detected max file descriptor number: 65536</div><div class="line">lock engine: pthread robust mutexes</div><div class="line">thunder lock: disabled (you can enable it with --thunder-lock)</div><div class="line">uwsgi socket 0 bound to TCP address 127.0.0.1:5000 fd 3</div><div class="line">Python version: 3.4.2 (default, Oct 19 2014, 14:03:53)  [GCC 4.9.1]</div><div class="line">Set PythonHome to venv</div><div class="line">Python main interpreter initialized at 0xbaf828</div><div class="line">python threads support enabled</div><div class="line">your server socket listen backlog is limited to 100 connections</div><div class="line">your mercy for graceful operations on workers is 60 seconds</div><div class="line">mapped 358400 bytes (350 KB) for 8 cores</div><div class="line">*** Operational MODE: preforking+threaded ***</div><div class="line">added ./ to pythonpath.</div><div class="line">WSGI app 0 (mountpoint=&apos;&apos;) ready in 5 seconds on interpreter 0xbaf828 pid: 3418 (default app)</div><div class="line">*** uWSGI is running in multiple interpreter mode ***</div><div class="line">spawned uWSGI master process (pid: 3418)</div><div class="line">spawned uWSGI worker 1 (pid: 3428, cores: 2)</div><div class="line">spawned uWSGI worker 2 (pid: 3429, cores: 2)</div><div class="line">spawned uWSGI worker 3 (pid: 3431, cores: 2)</div><div class="line">spawned uWSGI worker 4 (pid: 3432, cores: 2)</div></pre></td></tr></table></figure>
</li>
</ul>
<pre><code>- 停止

    - 如果还在同一个shell中，我们可以直接按 `Ctrl + C` 
    - 如果不在同一个shell中，可以这样结束掉 `killall -9 uwsgi`

启动成功之后就可以访问我们的Web应用了，默认地址是：http://127.0.0.1:5000 （这个地址和端口号是在我们的Flask应用中配配置的，这里不做介绍）。如果出现 `invalid request block size: 21573 (max 4096)...skip`这个错误，请将配置中的 `socket` 改为 `http`，具体可以参考[这里](http://stackoverflow.com/questions/15878176/uwsgi-invalid-request-block-size)。
</code></pre><h2 id="0x02-Nginx"><a href="/1970/01/01/[Flask]0x03树莓派上使用Nginx和uWSGI部署Flask应用/#0x02-Nginx" class="headerlink" title="0x02 Nginx"></a>0x02 Nginx</h2><ul>
<li><p>安装</p>
<p>  <code>sudo apt-get install ngnix</code></p>
</li>
<li><p>操作</p>
<ul>
<li><p>启动</p>
<p>  sudo /etc/init.d/nginx start<br>  sudo service nginx start</p>
</li>
<li><p>停止</p>
<p>  sudo /etc/init.d/nginx stop<br>  sudo service nginx stop</p>
</li>
<li><p>重启</p>
<p>  sudo /etc/init.d/nginx restart<br>  sudo service nginx restart</p>
<p>如果没问题，这个时候我们就可以打开浏览器访问：127.0.0.1，应该会看到一个静态页面。</p>
</li>
</ul>
</li>
<li><p>配置</p>
<p>  nginx 的配置文件时位于 <code>/etc/nginx/sites-available</code> 目录下的 <code>default</code> 文件，我们复制一份做修改，这里同样给一份最简单的配置：</p>
  <figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div></pre></td><td class="code"><pre><div class="line">server &#123;</div><div class="line">    listen 80;</div><div class="line"></div><div class="line">    server_name ttdevs.vicp.net;</div><div class="line"></div><div class="line">    # access_log logs/access.log compression;</div><div class="line"></div><div class="line">    #默认请求</div><div class="line">    location / &#123;</div><div class="line">            include uwsgi_params;</div><div class="line">            uwsgi_pass 127.0.0.1:5000;</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
</li>
</ul>
<pre><code>配置好这些之后重启我们的nginx服务：`sudo service nginx restart`。即可访问我们的web应用了。    
</code></pre><h2 id="0x03-总结"><a href="/1970/01/01/[Flask]0x03树莓派上使用Nginx和uWSGI部署Flask应用/#0x03-总结" class="headerlink" title="0x03 总结"></a>0x03 总结</h2><p>如果中间没有出错，你的Flask应用已经部署成功。到此，我们来梳理下这个流程。首先，我们安装Nginx，他直接处理用户发送的HTTP请求（HTTP服务器），并将请求按照我们的配置（nginx中的配置）交给uWSGI服务器（Web服务器），最后uWSGI将请求交给我们的Flask应用，由Flask应用进行逻辑处理，处理完之后再将结果返回给用户。这些，就是我对这个流程的理解，相信中间肯定有错误或者不到位的地方，在对这些知识有更进一步理解的时候我会返回及时更新。同时也欢迎各位指正～～</p>
<h2 id="0xFF-参考"><a href="/1970/01/01/[Flask]0x03树莓派上使用Nginx和uWSGI部署Flask应用/#0xFF-参考" class="headerlink" title="0xFF 参考"></a>0xFF 参考</h2><ol>
<li><a href="http://docs.jinkan.org/docs/flask/deploying/uwsgi.html" target="_blank" rel="external">http://docs.jinkan.org/docs/flask/deploying/uwsgi.html</a></li>
<li><a href="http://www.cnblogs.com/zhouej/archive/2012/03/25/2379646.html" target="_blank" rel="external">http://www.cnblogs.com/zhouej/archive/2012/03/25/2379646.html</a></li>
<li><a href="http://www.cnblogs.com/Ray-liang/p/4173923.html" target="_blank" rel="external">http://www.cnblogs.com/Ray-liang/p/4173923.html</a></li>
<li><a href="https://github.com/nginx/nginx/blob/master/conf/uwsgi_params" target="_blank" rel="external">https://github.com/nginx/nginx/blob/master/conf/uwsgi_params</a></li>
<li><a href="http://docs.jinkan.org/docs/flask/deploying/wsgi-standalone.html#deploying-proxy-setups" target="_blank" rel="external">http://docs.jinkan.org/docs/flask/deploying/wsgi-standalone.html#deploying-proxy-setups</a></li>
</ol>
<p><img src="https://raw.githubusercontent.com/ttdevs/ttdevs.github.io/common/images/logo.png" alt="Create by ttdevs"></p>

          </section>
        </article>
        

       
        <div class="pager">
          
            <a class="post-prev pager-item" href="/1970/01/01/[Flask]0x01FlaskMail/" >
              <strong class="article-nav-caption">上一篇</strong>
              <p class="post-nav-title">「Flask」0x01FlaskMail</p>
            </a>
          
          
            <a class="post-next pager-item" href="/1970/01/01/[玩转树莓派]0x04还我80端口/">
              <strong class="article-nav-caption">下一篇</strong>
              <p class="post-nav-title">「玩转树莓派」0x04还我80端口</p>
            </a>
          
        </div>
        

         <!-- comments -->
        <div class="comment-section">
  
    


</div>

    </div>
    
    <aside>
        <div id="toc">
        </div>
    </aside>
    
</div>

                </div>
            </div>
        </div>
        <footer class="footer">
    <p>由<a href="http://hexo.io/" target="_blank">Hexo</a>强力驱动，搭载<a href="https://github.com/wayou/hexo-theme-gstyle">gstyle</a>主题</p>
    <p>
        &copy; 2017 ttdevs
    </p>
</footer>
<script src="/lib/jquery.js"></script>
<script src="/lib/waves.js"></script>
<script src="/lib/jquery-ui.js"></script>
<script src="/lib/jquery.tocify.js"></script>
<script src="/js/main.js"></script>

    </body>
</html>
